package com.repro.lib_base.liveData

import android.os.Looper
import androidx.lifecycle.LifecycleOwner

//创建一个全局的LiveData
/**
 * 一个全局的liveData 注册分发事件，通过全局注册和监听可以做到任意地方接受 生命周期随application生命周期一起
 *
 * liveData会有两个问题一个是粘性事件，一个是数据倒灌
 * 数据倒灌是指，界面销毁重建时还能收到之前过期的事件，程序上对这种事件可能会造成界面数据显示错误或者算法错误。
 * 粘性事件是指调用setValue之后才注册observer观察者这个时候会触发之前发送的事件这称为粘性事件，
 *      注意： 数据倒灌是因为粘性事件所产生的，但是为了解决数据倒灌不建议使用全局的liveData或者单例的livedata
 *      |以及为什么在 “页面通信” 的场景下，不用静态单例、不用 LiveDataBus
 *
 *
 * 如果出现Caused by: java.lang.IllegalArgumentException: Cannot add the same observer with different lifecycles
 * 检查是否观察写的是空的观察者
 *       LiveDataBusEvent.get().with("nihao2", Int::class.java)
 *               .observe(this, { t ->
 *                 //TDOD 这里一定要写方法如果只是打印会导致出现以上错误
 *                  DLog.e("----$t+====>${t.javaClass}")
 *      })
 */
class LiveDataBusEvent {

    companion object {
        private var instance: LiveDataBusEvent? = null
            get() {
                if (field == null) {
                    field = LiveDataBusEvent()
                }
                return field
            }

        @Synchronized
        fun get(): LiveDataBusEvent {
            return instance!!
        }
    }

    //创建一个存储对象,全局存放共同一个LiveDataBus
    private var hashMap: HashMap<String, NoStickyLiveData<Any>> = HashMap()

    /**
     * 注册事件
     *  LiveDataBusEvent.get().with("nihao", String::class.java).postValue("1sasa")
     *  LiveDataBusEvent.get().with("nihao2", Int::class.java).postValue(i++)
     *  @param key 注册事件的key
     *  @param clazz 这里主要是用作类型推断使用的
     *         如果不传clazz warn: Not enough information to infer type variable T
     *
     *  LiveDataBusEvent.get().with("nihao2", Int::class.java)
     *      .observe(this, { t ->
     *      DLog.e("----$t+====>${t.javaClass}")
     *     })
     *
     */
    @Synchronized
    fun <T> getChannel(key: String, clazz: Class<T>): NoStickyLiveData<T> {
        if (hashMap[key] == null) {
            hashMap[key] = NoStickyLiveData<Any>()
        }
        return hashMap[key] as NoStickyLiveData<T>
    }

    @Synchronized
    fun defaultChannel(key: String): NoStickyLiveData<Any> {
        if (hashMap[key] == null) {
            hashMap[key] = NoStickyLiveData<Any>()
        }
        return hashMap[key] as NoStickyLiveData<Any>
    }

    @Synchronized
    fun register(key: String, value: Any) {
        val mutableLiveData = getChannel(key, value.javaClass)
        if (isMainThread()) {
            mutableLiveData.setValue(value)
        } else {
            getChannel(key, value.javaClass).setValue(value)
        }
    }

    @Synchronized
    fun <T> observe(key: String, clazz: Class<T>, owner: LifecycleOwner, callback: (t: T) -> Unit) {
        getChannel(key, clazz).observe(owner, {
            callback(it)
        })
    }

    /**
     * 移除消息
     */
    @Synchronized
    fun remove(key: String, owner: LifecycleOwner) {
        if (hashMap[key] != null) {
            hashMap[key]!!.removeObservers(owner)
            hashMap.remove(key)
        }
    }

    /**
     * 重置hashMap
     */
    fun reset() {
        hashMap.clear()
    }

    /**
     * 判断是否是主线程 获取当前looper是否与getMainLooper相等
     */
    fun isMainThread(): Boolean {
        return Looper.myLooper() == Looper.getMainLooper()
    }
}